package com.gr.staffpm.projects.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.gr.staffpm.dao.HibernateDao;
import com.gr.staffpm.datatypes.Project;
import com.gr.staffpm.datatypes.Task;
import com.gr.staffpm.datatypes.User;

@Repository("projectDAO")
@SuppressWarnings("unchecked")
public class HibernateProjectDAO extends HibernateDao implements ProjectDAO {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public Project getProject(int projectId) {
        return (Project) getSession().get(Project.class, projectId);
    }

    @Override
    public Project findProject(String projectName) {
        Assert.hasText(projectName);
        Criteria crit = getSession().createCriteria(Project.class);
        crit.add(Restrictions.eq(Project.NAME, projectName));
        return (Project) crit.uniqueResult();
    }

    @Override
    public void createProject(Project project) {
        getSession().save(project);
    }

    @Override
    public List<Project> getAllProjects(User user) {
        Criteria crit = getSession().createCriteria(Project.class);
        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        return crit.list();
    }

    @Override
    public List<Project> getAllProjects(User user, String property, boolean ascending) {

        Criteria crit = getSession().createCriteria(Project.class);
        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        Order order;

        if (property == null) {
            if (ascending)
                order = Order.asc(Project.NAME);
            else
                order = Order.desc(Project.NAME);
        } else {
            if (ascending)
                order = Order.asc(property);
            else
                order = Order.desc(property);
        }

        crit.addOrder(order);
        return crit.list();
    }

    @Override
    public void deleteProject(int projectId) {
        Project project = getProject(projectId);
        if (project != null) {
            getSession().delete(project);
        }
    }

    @Override
    public void updateProject(Project project) {
        getSession().update(project);
    }

    @Override
    public List<Task> getAllTasks(Project project, String property, boolean ascending) {
        Criteria crit = getSession().createCriteria(Task.class);
        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        crit.add(Restrictions.eq(Task.PROJECT, project));
        Order order;

        if (property == null) {
            if (ascending)
                order = Order.asc(Task.NAME);
            else
                order = Order.desc(Task.NAME);
        } else {
            if (ascending)
                order = Order.asc(property);
            else
                order = Order.desc(property);
        }

        crit.addOrder(order);

        return crit.list();
    }

    @Override
    public List<Task> getTasksCreatedBetween(Project project, Date startDate, Date endDate) {
        Criteria crit = getSession().createCriteria(Task.class);
        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        crit.add(Restrictions.between(Task.CREATED, startDate, endDate));
        crit.add(Restrictions.eq(Task.PROJECT, project));
        crit.addOrder(Order.asc(Task.CREATED));
        return crit.list();
    }

    @Override
    public List<Task> getTasksResolvedBetween(Project project, Date startDate, Date endDate) {
        Criteria crit = getSession().createCriteria(Task.class);
        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        crit.add(Restrictions.between(Task.RESOLVED_DATE, startDate, endDate));
        crit.add(Restrictions.eq(Task.RESOLVED, true));
        crit.add(Restrictions.eq(Task.PROJECT, project));
        crit.addOrder(Order.asc(Task.RESOLVED_DATE));
        return crit.list();
    }

    @Override
    public Task loadTask(int id) {
        return (Task) getSession().get(Task.class, id);
    }

    @Override
    public boolean checkProjectExists(Project project) {
        Criteria crit = getSession().createCriteria(Project.class);
        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        crit.add(Restrictions.eq(Project.KEY, project.getKey()));
        return crit.uniqueResult() != null;
    }

}
